global pic_init
global write_m_EOI
global write_s_EOI
global read_m_ISR
global read_s_ISR
global read_m_IRR
global read_s_IRR
global read_m_IMR
global write_m_IMR
global read_s_IMR
global write_s_IMR
global set_m_smm
global enable_int0x20


; 初始化可编程中断控制器 8259A - 级联
pic_init:
    push ebp
    mov ebp, esp
    push ax
.8259a_m_init:  ; 8259A 主片初始化
    mov al, 0x11  ; ICW1：边沿触发，级联，需要 ICW4
    out 0x20, al
    mov al, 0x20  ; ICW2：起始中断向量号为 0x20
    out 0x21, al
    mov al, 0x04  ; ICW3：IRQ2 接从片
    out 0x21, al
    mov al, 0x11  ; ICW4：8086模式，正常 EOI，非缓冲模式，特殊全嵌套模式
    out 0x21, al
    
    ; 默认屏蔽 0x20 号时钟中断
    call read_m_IMR
    or al, 00000001b
    call write_m_IMR

.8259a_s_init:  ; 8259A 从片初始化
    mov al, 0x11  ; ICW1：边沿触发，级联，需要 ICW4
    out 0xA0, al
    mov al, 0x28  ; ICW2：起始中断向量号为 0x28
    out 0xA1, al
    mov al, 0x02  ; ICW3：设置从片连接到主片 IRQ2 引脚
    out 0xA1, al
    mov al, 0x01  ; ICW4：8086模式，正常 EOI，非缓冲模式，全嵌套模式
    out 0xA1, al

    pop ax
    leave
    ret

; 手动结束主片中断
write_m_EOI:
    push ebp
    mov ebp, esp
    push ax
    mov al, 0x20  ; OCW2：固定优先级方式，结束中断，清 ISR 相应位
    out 0x20, al  ; 端口号：0x20
    pop ax
    leave
    ret

; 手动结束从片中断
write_s_EOI:
    push ebp
    mov ebp, esp
    push ax
    mov al, 0x20  ; OCW2：固定优先级方式，结束中断，清 ISR 相应位
    out 0xA0, al  ; 端口号：0xA0
    pop ax
    leave
    ret

; 读主片 ISR 寄存器的值，返回值存入 al 寄存器
read_m_ISR:
    push ebp
    mov ebp, esp
    mov al, 0x0B  ; OCW3：RR=1，RIS=1，读取 ISR 寄存器的值
    out 0x20, al  ; 端口号：0x20
    jmp $+2       ; jmp 指令占 2 个字节，$ 表示当前位置，这里就是起延时作用，给与端口处理时间
    in al, 0x20  ; 端口号：0x20 
    leave 
    ret

; 读从片 ISR 寄存器的值，返回值存入 al 寄存器
read_s_ISR:
    push ebp
    mov ebp, esp
    mov al, 0x0B  ; OCW3：RR=1，RIS=1，读取 ISR 寄存器的值
    out 0xA0, al  ; 端口号：0xA0
    jmp $+2       ; jmp 指令占 2 个字节，$ 表示当前位置，这里就是起延时作用，给与端口处理时间
    in al, 0xA0   ; 端口号：0xA0
    leave
    ret

; 读主片 IRR 寄存器的值，返回值存入 al 寄存器
read_m_IRR:
    push ebp
    mov ebp, esp
    mov al, 0x0A  ; OCW3：RR=1，RIS=0，读取 IRR 寄存器的值
    out 0x20, al  ; 端口号：0x20
    jmp $+2       ; jmp 指令占 2 个字节，$ 表示当前位置，这里起延时作用，给与端口处理时间
    in al, 0x20   ; 端口号：0x20 
    leave
    ret

; 读从片 IRR 寄存器的值，返回值存入 al 寄存器
read_s_IRR:
    push ebp
    mov ebp, esp
    mov al, 0x0A  ; OCW3：RR=1，RIS=0，读取 IRR 寄存器的值
    out 0xA0, al  ; 端口号：0xA0
    jmp $+2       ; jmp 指令占 2 个字节，$ 表示当前位置，这里起延时作用，给与端口处理时间
    in al, 0xA0   ; 端口号：0xA0
    leave
    ret

; 读主片 IMR 寄存器的值，返回值存入 al 寄存器
read_m_IMR:
    push ebp
    mov ebp, esp
    in al, 0x21  ; 端口号：0x21
    leave
    ret

; 将 al 寄存器的值写入主片 IMR 中
write_m_IMR:
    push ebp
    mov ebp, esp
    out 0x21, al ; 端口号：0x21
    leave
    ret

; 读从片 IMR 寄存器的值，返回值存入 al 寄存器
read_s_IMR:
    push ebp
    mov ebp, esp
    in al, 0xA1  ; 端口号：0xA1
    leave
    ret

; 将 al 寄存器的值写入从片 IMR 中
write_s_IMR:
    out 0xA1, al ; 端口号：0xA1
    ret

; 设置主片工作在特殊屏蔽模式
set_m_smm:
    push ebp
    mov ebp, esp
    push ax
    mov al, 0x68  ; ESMM=1，SMM=1
    out 0x20, al  ; 端口号：0x20
    pop ax
    leave
    ret

; 取消屏蔽 0x20 号时钟中断
enable_int0x20:
    push ebp
    mov ebp, esp
    call read_m_IMR
    and al, 11111110b
    call write_m_IMR
    leave
    ret